package bsk;

import java.math.BigInteger;
import java.security.SecureRandom;
import komunikaty.Card;

/**
 *
 * @author Lukasz
 */
public class CVoting {
    //szyfrowanie wiadomości

    public static BigInteger szyfruj(BigInteger message, BigInteger wykPublic, BigInteger modul) {
        return message.modPow(wykPublic, modul);
    }

    //odszyfrowanie wiadomości
    public static BigInteger odszyfruj(BigInteger messageSzyfrowana, BigInteger wykPrivate, BigInteger modul) {
        return messageSzyfrowana.modPow(wykPrivate, modul);
    }

    //losowanie R do zaciemniania
    public static BigInteger losowanieR(BigInteger modul) {
        BigInteger R;
        BigInteger rand;
        BigInteger gcd;

        SecureRandom random = new SecureRandom();

        do {
            byte[] BytesRandom = new byte[100];
            random.nextBytes(BytesRandom);
            rand = new BigInteger(1, BytesRandom);
            gcd = rand.gcd(modul);
            R = rand;
        } while (!gcd.equals(BigInteger.ONE) || rand.compareTo(modul) >= 0 || rand.compareTo(BigInteger.ONE) <= 0);

        return R;
    }
    
    //generowanie tablicy różnych r
    public static BigInteger[] RTablica(int ile, BigInteger module){
        BigInteger[] RR = new BigInteger[ile];
        RR[0] = losowanieR(module);
        BigInteger R = losowanieR(module);
        boolean var = true;
        for (int i = 1; i < ile; i++) {
            while (var) {
                var = false;
                for (int j = 0; j < i; j++) {
                    if (R.compareTo(RR[j])==0) {
                        var = true;
                        R = losowanieR(module);
                        break;
                    }
                }
            }
            var = true;
            RR[i] = R;
        }
        return RR;
    }

    //zaciemnianie wiadomości: m'=mr^e mod(n)
    public static BigInteger zaciemniaj(BigInteger message, BigInteger R, BigInteger wykPublic, BigInteger modul) {
        return message.multiply(R.modPow(wykPublic, modul)).mod(modul);
    }

    //zdejmuje odślepienie podpsanej wiadomości: s=s'r^{-1} mod(n)
    public static BigInteger odslepPodpisane(BigInteger messagePodpisana, BigInteger R, BigInteger modul) {
        return messagePodpisana.multiply(R.modInverse(modul)).mod(modul);
    }
    
    //podpisuje wybraną wiadomość: f=s^E2 mod N2.
    public static BigInteger podpisanieWiadom(BigInteger message, BigInteger wykPublic2, BigInteger modul2) {
        return message.modPow(wykPublic2, modul2);
    }
    
    //zaciemnianie jednej karty do glosowania
    public static void zaslonKarte(Card karta, BigInteger R, BigInteger wykPublic, BigInteger modul){
        for (int i = 0; i < karta.votes.length; i++) {
            karta.votes[i].candidate = zaciemniaj(karta.votes[i].candidate, R, wykPublic, modul);
            karta.votes[i].serial = zaciemniaj(karta.votes[i].serial, R, wykPublic, modul);
        }
    }
    
    //zaciemnianie tablicy kart
    public static void zaslonKarty(Card[] karty, BigInteger[] R, BigInteger wykPublic, BigInteger modul){
        for (int i = 0; i < karty.length; i++) {
            zaslonKarte(karty[i], R[i], wykPublic, modul);
        }
    }
    
    //zdejmuje odślepienie jednej karty
    public static void odslepPodKarte(Card KartaPodpisana, BigInteger R, BigInteger modul) {
        for (int i = 0; i < KartaPodpisana.votes.length; i++) {
            KartaPodpisana.votes[i].candidate = odslepPodpisane(KartaPodpisana.votes[i].candidate, R, modul);
            KartaPodpisana.votes[i].serial = odslepPodpisane(KartaPodpisana.votes[i].serial, R, modul);
        }
    }
    
    //podpisuje wybrany głos
    public static void podpisanieGlosu(Card.Vote glos, BigInteger wykPublic2, BigInteger modul2) {
        glos.candidate = podpisanieWiadom(glos.candidate, wykPublic2, modul2);
        glos.serial = podpisanieWiadom(glos.serial, wykPublic2, modul2);
    }
    
}

